﻿using StructuredProgrammingAssignment.App_Start;
using StructuredProgrammingAssignment.Helpers;
using StructuredProgrammingAssignment.Linq;
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Linq;
using System.Linq.Dynamic;

namespace StructuredProgrammingAssignment.Controllers
{
    public class SPStuffController : SPApiController
    {
		protected Object[] GetStuffs(
			List<UserStuff> stuffList,

			string where = null,				// dynamic filter clause, this feature can be turn off via config
			string order = null,				// dynamic order clause, this feature can be turn off via config

			int categoryId = int.MinValue,		// filter stuffs by category

			string name = null,					// filter by name
			bool nameExact = false,				// search for exact stuff name if true

			string description = null,			// filter by description
			bool descriptionExact = false,		// search for exact stuff description if true

			DateTime? modifiedFrom = null,		// set minimum modified datetime
			DateTime? modifiedTo = null,		// set maximum modified datetime
			DateTime? createdFrom = null,		// set minimum created datetime
			DateTime? createdTo = null,			// set maximum created datetime

			decimal priceMin = decimal.MinValue,	// set minimum price
			decimal priceMax = decimal.MaxValue,	// set maximum price
			bool priceExclusive = true,			// exclusive or not

			string orderCol = "Name",			// order column
			string orderDir = "ASC",			// order direction
			int offset = 0,						// specifies the number of rows to skip
			int limit = 0						// the number of rows to be retrieved
		) {
			var stuffs = stuffList.AsQueryable();

			// where
			if (where != null) {
				if (!SPConfig.Settings.AllowDynamicQuery)
					return FailureResult("Dynamic query is not allowed.", "dynamic query is not allowed");

				int whereMaxLength = Convert.ToInt32(SPConfig.Settings.DynamicQuery.ValueDictionary()["whereMaxLength"]);

				if (where.Length > whereMaxLength)
					return FailureResult("Dynamic where clause is too long.", "dynamic where clause too long");

				stuffs = stuffs.Where(where);
			}

			// order
			if (order != null) {
				if (!SPConfig.Settings.AllowDynamicQuery)
					return FailureResult("Dynamic query is not allowed.", "dynamic query is not allowed");

				int orderMaxLength = Convert.ToInt32(SPConfig.Settings.DynamicQuery.ValueDictionary()["orderMaxLength"]);

				if (order.Length > orderMaxLength)
					return FailureResult("Dynamic order clause is too long.", "dynamic order clause too long");

			}

			// order
			if (order == null) {
				stuffs = stuffs.OrderBy(String.Format("{0} {1}", orderCol, orderDir));
			} else {
				stuffs = stuffs.OrderBy(String.Format("{0}, {1} {2}", order, orderCol, orderDir));
			}

			// categoryId
			if (categoryId != int.MinValue) {
				stuffs = (from s in stuffs
						  where s.CategoryId == categoryId
						  select s);
			}

			// name
			if (name != null) {
				if (nameExact) {
					stuffs = (from s in stuffs
							  where s.Name.Equals(name)
							  select s);
				} else {
					stuffs = (from s in stuffs
							  where s.Name.ToLower().Contains(name.ToLower())
							  select s);
				}
			}

			// description
			if (description != null) {
				if (descriptionExact) {
					stuffs = (from s in stuffs
							  where s.Description.Equals(description)
							  select s);
				} else {
					stuffs = (from s in stuffs
							  where s.Description.ToLower().Contains(description.ToLower())
							  select s);
				}
			}

			// modified time
			modifiedFrom = modifiedFrom ?? SqlDateTime.MinValue.Value;
			modifiedTo = modifiedTo ?? SqlDateTime.MaxValue.Value;
			stuffs = (from s in stuffs
					  where s.ModifiedDateTime >= modifiedFrom && s.ModifiedDateTime <= modifiedTo
					  select s);

			// created time
			createdFrom = createdFrom ?? SqlDateTime.MinValue.Value;
			createdTo = createdTo ?? SqlDateTime.MaxValue.Value;
			stuffs = (from s in stuffs
					  where s.CreatedDateTime >= createdFrom && s.CreatedDateTime <= createdTo
					  select s);

			// price
			if (priceExclusive) {
				stuffs = (from s in stuffs
						  where s.UnitPrice > priceMin && s.UnitPrice < priceMax
						  select s);
			} else {
				stuffs = (from s in stuffs
						  where s.UnitPrice >= priceMin && s.UnitPrice <= priceMax
						  select s);
			}

			// offset
			stuffs = stuffs.Skip(offset);

			// limit
			if (limit > 0) {
				stuffs = stuffs.Take(limit);
			}

			// Return list of stuffs
			List<Object> returnObjs = new List<Object>();
			foreach (UserStuff stuff in stuffs) {
				returnObjs.Add(SPHelper.JsonUserStuff(stuff));
			}
			if (returnObjs.Count == 0) returnObjs = null;

			return SuccessResult(returnObjs);
		} // GetStuffs

    }
}
